#ifndef __PROTOCOL_H
#define __PROTOCOL_H

#include <stdbool.h>
#include <stdint.h>
#include "cJSON.h"
#include <stdint.h>

#define CMD_LEN 256
#define URL_LEN 256
#define RESOLUTION_LEN 256
#define OUT_PATH_LEN 256
#define ERROR_INFO_LEN 2048
#define STREAM_INFO_LEN 40960

#define DEFINE_REQUEST_INIT(cmd) static msg_processing_t* req_##cmd##_init(req_##cmd##_t *ruc)\
{\
    extern int req_##cmd##_msg_to_do(msg_processing_t *msgp, response_t *resp);\
    extern int req_##cmd##_msg_to_struct(msg_processing_t *msgp, cJSON *obj);\
    extern int req_##cmd##_struct_to_msg(msg_processing_t *msgp, payload_t *payload, cJSON **obj);\
    msg_processing_t *msgp = (msg_processing_t *)ruc;\
    msgp->msg_to_do = req_##cmd##_msg_to_do;\
    msgp->msg_to_struct = req_##cmd##_msg_to_struct;\
    msgp->struct_to_msg  =req_##cmd##_struct_to_msg;\
    return msgp;\
    }

#define REQUEST_INIT(cmd) req_##cmd##_init(&req->payload.req_##cmd)

typedef enum {
    MEDIA_RET_SUCCESS = 0,
    MEDIA_RET_THREAD_ERROR,
    MEDIA_RET_NULL_PTR,
    MEDIA_RET_CMD_RUNNING,
    MEDIA_RET_CMD_STOPED,
    MEDIA_RET_CJSON_ERROR,
    MEDIA_RET_MSG_HANDLE_ERROR,
    MEDIA_RET_INTERNAL_ERROR,
    MEDIA_RET_CMD_NOT_SURPPORT
}media_ret_t;

typedef struct {
    bool rtsp_to_rtmp_run;
    bool rtsp_record_run;
    bool user_cmd_run;
} media_status_t;

typedef struct media media_t;
struct media {
    int (*rtsp_to_rtmp)(media_t *md, bool run, const char *rtsp_url, const char *rtmp_url, const char *recode);
    int (*rtsp_record)(media_t *md, bool run, const char *rtsp_url, const char *out_path);
    int (*rtsp_screenshot)(media_t *md, const char *rtsp_url, const char *out_path);
    int (*get_status)(media_t *md, media_status_t *status);
    int (*user_cmd)(media_t *md, bool run, const char *cmd);
    int (*stream_probe)(media_t *md, const char *rtsp_url, char *out_buf, uint32_t size);
};

typedef struct response response_t;
typedef struct payload payload_t;

typedef struct msg_processing msg_processing_t;
struct msg_processing {
    int (*msg_to_struct)(msg_processing_t *msgp, cJSON *obj);
    int (*msg_to_do)(msg_processing_t *msgp, response_t *resp);
    int (*struct_to_msg)(msg_processing_t *msgp, payload_t *resp, cJSON **obj);
} ;

typedef struct req_user_cmd {
    msg_processing_t msgp;
    bool run;
    char cmd[CMD_LEN];
} req_user_cmd_t;

typedef struct req_get_status {
    msg_processing_t msgp;
} req_get_status_t;

typedef struct req_rtsp_to_rtmp {
    msg_processing_t msgp;
    bool run;
    char rtsp_url[URL_LEN];
    char rtmp_url[URL_LEN];
    char recode[RESOLUTION_LEN];
} req_rtsp_to_rtmp_t;

typedef struct req_rtsp_record {
    msg_processing_t msgp;
    bool run;
    char rtsp_url[URL_LEN];
    char out_path[OUT_PATH_LEN];
} req_rtsp_record_t;

typedef struct req_rtsp_screenshot {
    msg_processing_t msgp;
    char rtsp_url[URL_LEN];
    char out_path[OUT_PATH_LEN];
} req_rtsp_screenshot_t;

typedef struct req_stream_probe {
    msg_processing_t msgp;
    char rtsp_url[URL_LEN];
} req_stream_probe_t;

typedef struct resp_user_cmd {
}resp_user_cmd_t;

typedef struct resp_get_status {
    bool rtsp_to_rtmp;
    bool rtsp_record;
    bool user_cmd;
} resp_get_status_t;

typedef struct resp_rtsp_to_rtmp {
}resp_rtsp_to_rtmp_t;

typedef struct resp_rtsp_record {
} resp_rtsp_record_t;

typedef struct resp_rtsp_screenshot {
} resp_rtsp_screenshot_t;

typedef struct resp_stream_probe {
    char info[STREAM_INFO_LEN];
} resp_stream_probe_t;

typedef struct request {
    char cmd[CMD_LEN];
    union {
        req_user_cmd_t req_user_cmd;
        req_get_status_t req_get_status;
        req_rtsp_to_rtmp_t req_rtsp_to_rtmp;
        req_rtsp_record_t req_rtsp_record;
        req_rtsp_screenshot_t req_rtsp_screenshot;
        req_stream_probe_t req_stream_probe;
    } payload;
}request_t;

struct payload {
    int result;
    char error[ERROR_INFO_LEN];
    union {
        resp_user_cmd_t resp_user_cmd;
        resp_get_status_t resp_get_status;
        resp_rtsp_to_rtmp_t resp_rtsp_to_rtmp;
        resp_rtsp_record_t resp_rtsp_record;
        resp_rtsp_screenshot_t resp_rtsp_screenshot;
        resp_stream_probe_t resp_stream_probe;
    } data;
} ;

struct response {
    char cmd[CMD_LEN];
    payload_t payload;
} ;

int protocol_register_media(media_t *md);

int protocol_msg_handle(const void *in, void * out, uint32_t out_buf_size);

const char *protocol_get_error_str(media_ret_t ret);

#endif // !__PROTOCOL_H
